package com.ionehe.group.common.uaa.ex.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Throwables;
import com.ionehe.group.common.io.Response;
import com.ionehe.group.common.uaa.ex.domain.service.AdminReadService;
import com.ionehe.group.common.uaa.ex.domain.service.UserReadService;
import com.ionehe.group.common.uaa.ex.dto.ManageInfoDTO;
import com.ionehe.group.common.uaa.ex.dto.UserDetailDTO;
import com.ionehe.group.common.uaa.ex.enums.ErrorMessages;
import com.ionehe.group.common.uaa.ex.exception.BusinessException;
import com.ionehe.group.common.user.c.sdk.uaa.utils.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Copyright (c) 2020 ionehe.com
 * Date: 2020/12/2
 * Time: 5:58 下午
 *
 * @author 2020年 <a href="mailto:a@ionehe.com">秀</a>
 */
@Component
@Slf4j
public class LoginUtils {
    @Autowired
    private UserReadService userReadService;
    @Autowired
    private AdminReadService adminReadService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private RedisUtils redisUtils;
    @Value("${redis.database:base}")
    private String redisDatabase;
    @Value("${redis.expire.common:86400}")
    private Long redisExpire;
    @Value("${redis.key.user:uaa:user}")
    private String redisKeyUser;
    @Value("${jwt.tokenLimit:-1}")
    private Integer tokenLimit;

    /**
     * 获取当前登陆用户
     *
     * @return 用户信息
     */
    public Response<UserDetailDTO> getCurrentUser() {
        String currentUserName = com.ionehe.group.common.user.c.sdk.uaa.utils.UaaLoginUtil.getCurrentUserName();

        if (StrUtil.isBlank(currentUserName)) {
            return Response.no(ErrorMessages.USER_NOT_LOGIN.toString());
        }

        // 先查开发者账号
        Response<ManageInfoDTO> adminRes = adminReadService.getAdminByUsername(currentUserName);
        if (!adminRes.success()) {
            return Response.no(adminRes.getMessage());
        } else {
            if (adminRes.getData() != null) return Response.yes(null);
        }

        // 再查非开发者账号
        if (adminRes.getData() == null) {
            return userReadService.getUserByUsername(currentUserName);
        }

        return Response.no(ErrorMessages.GET_USER_INFO_FAIL.toString());
    }

    /**
     * 账号登出
     *
     * @param token token
     * @return 成功或者失败
     */
    public Response<Boolean> logout(String token) {
        try {
            String account = jwtTokenUtil.getUserNameFromToken(token);
            List<Map<String, Date>> tokenList = getCacheToken(account);
            removeToken(token, tokenList);
            // 更新token缓存
            updateCacheToken(account, tokenList);
            return Response.yes(true);
        } catch (Exception e) {
            log.error("LoginUtil[]logout[]error! cause:{}", Throwables.getStackTraceAsString(e));
            return Response.no(false);
        }
    }

    /**
     * 用户登陆上限校验
     *
     * @param account 账号
     * @param token   token
     */
    public void tokenUpperLimitCheck(String account, String token) {
        List<Map<String, Date>> tokenList = getCacheToken(account);
        if (CollUtil.isNotEmpty(tokenList)) {
            removeExpiredToken(tokenList);
            if (tokenLimit != -1 && tokenList.size() == tokenLimit) {
                throw new BusinessException(ErrorMessages.USER_LOGIN_IS_UPPER_LIMIT.toString());
            }
        }
        Map<String, Date> map = new HashMap<>(1);
        map.put(token, jwtTokenUtil.getExpiredDateFromToken(token));
        tokenList.add(map);
        // 记录当前token
        updateCacheToken(account, tokenList);
    }

    /**
     * 移除过期的token
     *
     * @param tokenList token列表
     */
    private void removeExpiredToken(List<Map<String, Date>> tokenList) {
        List<Map<String, Date>> removeToken = new ArrayList<>();

        for (Map<String, Date> m : tokenList) {
            m.forEach((t, expired) -> {
                Date now = new Date();
                if (expired.before(now) || expired.equals(now)) {
                    removeToken.add(m);
                }
            });
        }
        for (Map<String, Date> m : removeToken) {
            tokenList.remove(m);
        }
    }

    /**
     * 更新缓存中的token
     *
     * @param account   账号
     * @param tokenList token列表
     */
    private void updateCacheToken(String account, List<Map<String, Date>> tokenList) {
        String key = redisDatabase + ":" + redisKeyUser + ":" + account + ":" + "token";
        redisUtils.set(0, key, tokenList, redisExpire);
    }

    /**
     * 移除token
     *
     * @param token     token
     * @param tokenList 当前token列表
     */
    private void removeToken(String token, List<Map<String, Date>> tokenList) {
        List<Map<String, Date>> removeToken = new ArrayList<>();

        // 删除token
        for (Map<String, Date> m : tokenList) {
            m.forEach((t, expired) -> {
                if (StrUtil.equals(t, token)) {
                    removeToken.add(m);
                }
            });
        }

        for (Map<String, Date> m : removeToken) {
            tokenList.remove(m);
        }
    }

    /**
     * 获取当前用户的token
     */
    private List<Map<String, Date>> getCacheToken(String account) {
        String key = redisDatabase + ":" + redisKeyUser + ":" + account + ":" + "token";
        Object o = redisUtils.get(0, key);
        if (Objects.isNull(o)) {
            return new ArrayList<>();
        }
        return (List<Map<String, Date>>) redisUtils.get(0, key);
    }


}
